/**
 * MIT License
 * 
 * Copyright (c) 2017 CaiDongyu
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package com.tunnel.home.core;
  
import java.text.SimpleDateFormat;
import java.util.Date;

import org.axe.extra.abc_thread.SerialExecutor;
import org.axe.extra.abc_thread.TaskPack;
import org.axe.extra.abc_thread.TaskPackBusController;
import org.axe.helper.ioc.BeanHelper;
import org.axe.util.CollectionUtil;
import org.axe.util.LogUtil;
import org.axe.util.StringUtil;

import com.tunnel.common.tunnel.TunnelDataQueueManager;
import com.tunnel.common.util.ContentFilterUtil;
import com.tunnel.common.util.HttpUtil;
import com.tunnel.home.common.Constant;
import com.tunnel.home.common.RedisUtil;
import com.tunnel.home.dao.DomainDao;
import com.tunnel.home.entity.User;
import com.tunnel.home.server.UserService;

import io.netty.channel.ChannelHandlerContext;  
  
public class TunnelServerHandler extends com.tunnel.server.tunnel.TunnelServerHandler{

	@Override
    protected boolean registerMsg(ChannelHandlerContext ctx, byte[] data) {
    	//客户端来的注册信息
        String[] split = new String(data).split(Constant.SPLIT_FLAG);
		//抽离出账户密码，然后验证
        //split后格式：[clientName,hostAry,tcpAry,username,password]
        do{
	        if(split.length<5){
	        	TunnelDataQueueManager.commitData(TunnelDataQueueManager.REGISTER_MSG, ctx, "REGISTER FAILED:用户名或密码未填写".getBytes());
	        	break;
	        }
	        
	        //账号密码校验
	        String username = split[3];
	        String password = split[4];
	        UserService userService = BeanHelper.getBean(UserService.class);
	        User user;
			try {
				user = userService.checkUserAuth(username, password);
			} catch (Exception e1) {
				String error = "REGISTER FAILED:"+e1.getMessage();
				TunnelDataQueueManager.commitData(TunnelDataQueueManager.REGISTER_MSG, ctx, error.getBytes());
				break;
			}
			
			//检查域名是否属于自己申请的
			if(StringUtil.isEmpty(split[1])){
				TunnelDataQueueManager.commitData(TunnelDataQueueManager.REGISTER_MSG, ctx, "REGISTER FAILED:域名配置项空".getBytes());
	        	break;
			}
			String[] hostAry = split[1].split(",");
			for(int i=0;i<hostAry.length;i++){
				hostAry[i] = hostAry[i].replaceAll("\\.tunnel\\.cool", "");
			}
			DomainDao domainDao = BeanHelper.getBean(DomainDao.class);
			int count = domainDao.count(user.getId(), CollectionUtil.convertList(hostAry));
			if(count != hostAry.length){
				TunnelDataQueueManager.commitData(TunnelDataQueueManager.REGISTER_MSG, ctx, "REGISTER FAILED:域名配置错误，请检查域名是否正确".getBytes());
	        	break;
			}
			
			if(user.getStatus() == 0){
				//通过checkUserAuth，但是status是0，每天可以连接1次，1次10分钟
				SimpleDateFormat sdf = new SimpleDateFormat("dd");
				String day = sdf.format(new Date());
				String connectionStartTime = RedisUtil.getString(user.getId()+Constant.USER_STATUS_0_CONNECTION+day);
				long canConnectionTime = Constant.MIN_SECONDS_OF_10_MINUTES;//默认可以连接10分钟
				long nowTime = System.currentTimeMillis();
				if(StringUtil.isNotEmpty(connectionStartTime)){
					//说明已经连接过了，就需要检查已经连接了多少时间了
					Long startTime = Long.valueOf(connectionStartTime);
					//这个时间是不管你中间有没有断过的，只看你今天第一次连接，到现在的时间
					long hasConnectedTime = nowTime - startTime;
					if(hasConnectedTime> Constant.MIN_SECONDS_OF_10_MINUTES){
						String error = "REGISTER FAILED:您的会员已经到期，今日免费次数已经用完。";
						TunnelDataQueueManager.commitData(TunnelDataQueueManager.REGISTER_MSG, ctx, error.getBytes());
						break;
					}else{
						//如果还没到10分钟，还可以连接，但是要更新剩余时间
						canConnectionTime = canConnectionTime-hasConnectedTime;
					}
				}else{
					//空的，那么就记录下这是今天第一次，连接请求的时间
					RedisUtil.setKeyValue(user.getId()+Constant.USER_STATUS_0_CONNECTION+day, String.valueOf(nowTime), Constant.SECONDS_OF_24_HOURS);
				}
				
				//账号已经过期，10分钟主动断掉连接
				long closeTime = canConnectionTime;//应为canConnectionTime不是final的，必须用一个final接一下
				BeanHelper.getBean(TaskPackBusController.class).addTaskPack(new TaskPack("Status0User10MinCloseCtx") {
					private long startTime = nowTime;
					private boolean canClose = false;
					private long waiteTime = closeTime;
					
					@Override
					public boolean task(SerialExecutor executor) {
						long nowTime = System.currentTimeMillis();
						if(nowTime-this.startTime > this.waiteTime){
							if(!this.canClose){
								//执行一次通知
								try {
									TunnelDataQueueManager.commitData(TunnelDataQueueManager.REGISTER_MSG, ctx, "通知：会员已过期".getBytes());
								} catch (Exception e) {}
								this.startTime = nowTime;
								//下次就关闭了
								this.canClose = true;
								this.waiteTime = 10000;//等待10秒后，就关闭
								return true;
							}else{
								try {
									ctx.close();
								} catch (Exception e) {}
								return false;
							}
						}else{
							return true;
						}
					}
					
				});
			}
	        
			//都通过，完成注册
	        boolean success = super.registerMsg(ctx, data);
	        return success;
        }while(false);
        return false;
	}
	
	@Override
	protected void httpDataMsg(ChannelHandlerContext ctx, byte[] data) {
		//前16个字符是
		//requestId 时间戳+三位随机数，代表http请求的编号 占16位
		if(data.length >= 16){
			byte[] requestIdBytes = new byte[16];
			System.arraycopy(data, 0, requestIdBytes, 0, 16);
			
			byte[] dataBytes = new byte[data.length-16];
			if(dataBytes.length>0){
				System.arraycopy(data, 16, dataBytes, 0, dataBytes.length);
			}
			
			byte[] httpEndFlagBytes = new byte[Constant.HTTP_RESPONSE_END_FLAG_BYTES.length];
			boolean httpEnd = false;
			if(dataBytes.length >= Constant.HTTP_RESPONSE_END_FLAG_BYTES.length){
				System.arraycopy(dataBytes, dataBytes.length-Constant.HTTP_RESPONSE_END_FLAG_BYTES.length, httpEndFlagBytes, 0, Constant.HTTP_RESPONSE_END_FLAG_BYTES.length);
				String httpEndFlag = new String(httpEndFlagBytes);
				if(httpEndFlag.equals(Constant.HTTP_RESPONSE_END_FLAG)){
					httpEnd = true;
					//说明结束了，去掉结束的表示数据
					byte[] newDataBytes = new byte[dataBytes.length-Constant.HTTP_RESPONSE_END_FLAG_BYTES.length];
					System.arraycopy(dataBytes, 0, newDataBytes, 0, newDataBytes.length);
					dataBytes = newDataBytes;
				}
			}
			
			//到这里dataBytes是要返回给浏览器的内容了
			//开始检查
			String content = new String(dataBytes);
			LogUtil.log("检查内容>>>>");
			LogUtil.log(content);
			boolean isHtml = ContentFilterUtil.checkIsHtml(content);
			if(isHtml){
				LogUtil.log("拦截到内容");
				LogUtil.log(content);
				dataBytes = HttpUtil.response200("禁止访问Html内容，请遵守网站使用规定");
			}
			
			//解析完数据接口
			//开始查找浏览器连接，回传tunnel-client给过来的数据
			returnHttpDataToBroswer(requestIdBytes, dataBytes, httpEnd, ctx);
		}
	}
    
}  